<?php
/**
 * Copyright (c) 2006-2007, Julien PORTALIER
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright    Copyright (c) 2006-2007, Julien PORTALIER
 * @link         http://featherphp.googlecode.com/
 * @license      http://www.opensource.org/licenses/mit-license.php The MIT License
 */

/**
 * Framework's Rendering system (View).
 */
class View extends BaseCallback
{
	public $controller;
	public $here;
	
	public $params;
	public $data;
	public $load;
	
	public $viewVars  = array();
	public $viewPath  = '';
	public $templates = ''; 
	
	protected $viewVarsLayout = array();
	
	function __construct(Controller $controller=null)
	{
		# loader
		$this->load = Load::getInstance();
		$this->load->view = $this;
		
		# controller
		if ($controller)
		{
			$this->controller =  $controller;
			$this->here       =  $controller->here;
			$this->params     =& $controller->params;
			$this->viewPath   =  $controller->viewPath;
			$this->templates  =  $controller->_templates;
		}
		
		# view path
		$this->basePath = APP.(empty(Load::$plugin) ? '' : 'plugins'.DS.Load::$plugin.DS).'views'.DS;
	}
	
	function set($name, $value)
	{
		$this->viewVars[$name] = $value;
	}
	
	function get($name)
	{
		return isset($this->viewVars[$name]) ? $this->viewVars[$name] : null;
	}
	
	function setForLayout($name, $value)
	{
		$this->viewVarsLayout[$name] = $value;
	}
	
	function yield($name, $value=null)
	{
		if ($value !== null) {
			return $this->yields[$name] = $value;
		}
		return isset($this->yields[$name]) ? $this->yields[$name] : null;
	}
	
	function render($action, $layout, &$viewVars, $format=null)
	{
		# vars
		$this->viewVars =& $viewVars;
		
		# helpers
		$this->load->helpers();
		
		if (isset($this->controller))
		{
			# components
			$components = array_merge(Core::$components, $this->controller->components);
			foreach($components as $c)
				$this->set($c, $this->controller->$c);
		}
		
		if (isset($format))
		{
			$format = strtolower($format);
			$this->set('_rest_format', $format);
		}
		
		if (!empty($action))
		{
			$action = $this->viewPath.DS.$action;
			
			if (isset($format))
				$action .= ".$format";
		}
		
		# view + layout
		$this->callback('beforeRender');
		$render = $this->__render($action, $layout);
		$this->callback('afterRender', &$render);
		
		echo $render;
	}
	
	# elements
	
	function elementExists($element)
	{
		return (file_exists($this->basePath.'elements'.DS."$element.thtml")
			or file_exists(APP.'views'.DS.'elements'.DS."$element.thtml")
			or file_exists(FEATHER.'views'.DS.'elements'.DS."$element.thtml"));
	}
	
	function renderElement($element, $viewVars=null)
	{
		return $this->__render('elements'.DS.$element, null, $viewVars, false);
	}
	
	# partials
	
	function partialExists($partial)
	{
		return (file_exists($this->basePath.$this->viewPath.DS."_$partial.thtml")
			or file_exists(FEATHER.'views'.DS.$this->viewPath.DS."_$partial.thtml"));
	}
	
	function renderPartial($partial, $viewVars=null)
	{
		return $this->__render($this->viewPath.DS."_$partial", null, $viewVars, true);
	}
	
	# internals
	
	protected function __render($_file, $_layout=null, $_viewVars=null, $_template=true)
	{
		# vars
		foreach(array_keys($this->viewVars) as $var)
			$$var =& $this->viewVars[$var];
		
		if (!empty($_viewVars))
		{
			foreach(array_keys($_viewVars) as $var)
				$$var =& $_viewVars[$var];
		}
		
		if (isset($this->controller))
		{
			$data =& $this->controller->data;
			$title_for_layout = $this->controller->pageTitle;
		}
		
		# view, element or partial
		if (!empty($_file))
		{
			ob_start();
			
			if (file_exists($this->basePath."$_file.thtml"))
			{
				require $this->basePath."$_file.thtml";
			}
			elseif (strpos($_file, 'elements'.DS) === 0 and file_exists(APP.'views'.DS."$_file.thtml"))
			{
				require APP.'views'.DS."$_file.thtml";
			}
			elseif ($_template)
			{
				if (!empty($this->templates))
					$_file = preg_replace(':^([^'.DS.']+'.DS.'):', $this->templates.DS, $_file);
				
				if (file_exists(FEATHER.'views'.DS.'templates'.DS."$_file.thtml"))
					require FEATHER.'views'.DS.'templates'.DS."$_file.thtml";
				elseif (DEBUG)
					trigger_error(sprintf("Unable to find view '%s'.", $_file), E_USER_ERROR);
				else
					Error::show(404);
			}
			else
			{
				if (file_exists(FEATHER.'views'.DS."$_file.thtml"))
					require FEATHER.'views'.DS."$_file.thtml";
				elseif (DEBUG)
					trigger_error(sprintf("Unable to find view '%s'.", $_file), E_USER_ERROR);
				else
					Error::show(404);
			}
			$content_for_layout = ob_get_clean();
		}
		elseif (!isset($content_for_layout))
		{
			$content_for_layout = '';
		}
		
		# layout?
		if (!is_null($_layout))
		{
			foreach($this->viewVarsLayout as $k => $v)
			{
				$k = "{$k}_for_layout";
				$$k = $v;
			}
			
			ob_start();
			
			if (file_exists(APP.'views'.DS.'layouts'.DS."$_layout.thtml"))
				require APP.'views'.DS.'layouts'.DS."$_layout.thtml";
			elseif (file_exists(FEATHER.'views'.DS.'templates'.DS.'layouts'.DS."$_layout.thtml"))
				require FEATHER.'views'.DS.'templates'.DS.'layouts'.DS."$_layout.thtml";
			elseif (DEBUG)
				trigger_error(sprintf("Unable to find layout '%s'.", $_layout), E_USER_ERROR);
			else Error::show(404);
			
			return ob_get_clean();
		}
		
		return $content_for_layout;
	}
}
?>
